/***************************************************************************
 *   Copyright (C) 2007 by Warren Kenny   *
 *   warren.kenny@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef GSSTRING_H
#define GSSTRING_H

#include <gsCore/gsCore.h>
#include <gsCore/gsException.h>

#include <gsContainer/gsContainer.h>

#include <iostream>

#define GS_STRING_NULL_TERMINATOR '\0'
#define GS_STRING_NULL_TERMINATOR_BUFFER_LENGTH 1

class gsString
{
public:
	
	///
	/// Constructor(s)
	///
	
	/**
	 *        Default Constructor
	 */
	gsString();
	
	/**
	 *        Constructor which initializes the object's storage using the provided single character
	 * @param character The character
	 */
	gsString( const gsChar character );
	
	/**
	 * 	Constructor which initializes the object's storage using the provided character array
	 * @param string Character array
	 */
	gsString( const gsChar* string );
	
	/**
	 * 	Constructor which initializes the object's storage using the provided gsString
	 * @param other The other gsString
	 */
	gsString( const gsString &other );
	
	/**
	 * 	Constructor which initializes the object's storage using the first \a length characters from \a string, optionally
	 *	starting from the point \a index within the array
	 * @param length The number of characters to copy from \a string
	 * @param string The string to use during initialization
	 * @param index Specifies where to begin copying characters from the provided character array, defaults to zero
	 */
	gsString( const gsUInt length, const gsChar* string, const gsUInt index = 0 );
	
	/**
	 * 	Constructor which initializes the object's storage using the first \a length characters from \a string, optionally
	 *	starting from the point \a index within the string
	 * @param length The number of characters to copy from \a string's buffer
	 * @param string The string to use during initialization
	 * @param index Specifies where to begin copying characters from the provided character array, defaults to zero
	 */
	gsString( const gsUInt length, const gsString& string, const gsUInt index = 0 );
		
	
	///
	///	Operator(s)
	///
	
	/**
	 *        Assignment operator, creates a gsString object containing the same character sequence as \a other
	 * @param other The other gsString
	 * @return A reference to the duplicate gsString object
	 */
	gsString& operator=( const gsString& other );
	
	/**
	 *	  Comparison operator, checks whether the given gsString object contains an identical character sequence
	 * @param other The other gsString object
	 * @return 	True - If the given gsString contains an identical character sequence
	 *		False - Otherwise
	 */
	gsBool operator==( const gsString& other );
	
	
	/**
	 *	  Comparison operator, checks whether the given gsString object contains a different character sequence
	 * @param other The other gsString object
	 * @return 	True - If the given gsString contains a different character sequence
	 *		False - Otherwise
	 */
	gsBool operator!=( const gsString& other );
	
	/**
	 * 	Compares this gsString to another lexicographically
	 * @param other The other gsString
	 * @return 	True - If this gsString is greater than \a other 
	 *		False - Otherwise
	 */
	gsBool operator>( const gsString& other );
	
	/**
	 * 	Compares this gsString to another lexicographically
	 * @param other The other gsString
	 * @return 	True - If this gsString is greater than or equal to \a other 
	 *		False - Otherwise
	 */
	gsBool operator>=( const gsString& other );
	
	/**
	 * 	Compares this gsString to another lexicographically
	 * @param other The other gsString
	 * @return 	True - If this gsString is less than \a other 
	 *		False - Otherwise
	 */
	gsBool operator<( const gsString& other );
	
	/**
	 * 	Compares this gsString to another lexicographically
	 * @param other The other gsString
	 * @return 	True - If this gsString is less than or equal to \a other 
	 *		False - Otherwise
	 */
	gsBool operator<=( const gsString& other );
	
	/**
	 *        Concatenates the contents of \a other to this gsString
	 * @param other The other gsString
	 * @return A reference to the new gsString object
	 */
	gsString& operator+( const gsString& other );
	
	/**
	 *        Concatenates the contents of \a other to this gsString
	 * @param other The character
	 * @return A reference to the new gsString object
	 */
	gsString& operator+( const gsChar& other );
	
	/**
	 *        Concatenates the contents of \a other to this gsString
	 * @param other The character array
	 * @return A reference to the new gsString object
	 */
	gsString& operator+( const gsChar* other );
		
	/**
	 *        Returns the character at the given index within the gsString
	 * @param index The index from which to retrieve the character
	 * @return The requested character
	 */
	gsChar& operator[]( gsUInt index );
		
	/**
	 *        Sends the contents of this gsString to the given output stream
	 * @param dest The destination output stream the string will be sent to
	 * @param string The gsString to be sent to the output stream
	 * @return Output stream reference
	 */
	friend std::ostream& operator<<( std::ostream& dest, const gsString& string )
	{
		dest << string.m_buffer;
	}
	
	///
	///	Accessor Method(s)
	///
	
	/**
	 *        Get the total storage capacity of this string
	 * @return The string's storage capacity
	 */
	gsUInt getCapacity() const;
	
	/**
	 *        Get the number of characters contained in this string
	 * @return The number of characters contained in this string
	 */
	gsUInt getSize() const;
	
	///
	///	Miscellaneous Method(s)
	///
	
	/**
	 *        Increases the internal capacity of this gsString
	 * @param increment The number of additional characters this gsString should be able to hold
	 */
	void increaseCapacity( gsUInt increment );
	
	/**
	 *        Explodes the gsString around the given delimiter, the string fragments produced by this operation are stored in \a container
	 * @param delimiter The delimiter character
	 * @param container The container into which the produced gsString fragments are stored
	 * @return The number of fragments produced
	 */
	gsUInt explode( gsChar delimiter, gsContainer< gsString >& container );
	
	/**
	 *        Gets the length of the given null-terminated character array 
	 *	  Warning: This function may cause a segmentation fault if the provided character array is not null-terminated, use
	 *	  stringSize( const gsChar, const gsUInt ) to avoid this
	 * @param string The character array to assess
	 * @param searchLimit The buffer depth limit to be used when counting characters, used to avoid segfaults
	 * @return The size of the character array or -1 on failure ( searchLimit reached )
	 */
	static inline gsInt stringSize( const gsChar* string, const gsUInt searchLimit = 0 );
	
	/**
	 *        Copies the contents of one character array into another, using an optional copyLimit parameter to prevent segfaults
	 * @param destination The destination buffer
	 * @param source The source buffer
	 * @param  copyLimit The copy limit
	 * @return A pointer to the first character in the destination buffer
	 */
	static inline gsChar* stringCopy( gsChar* destination, const gsChar* source, const gsUInt copyLimit = 0 );
	
	/**
	 *        Compares two null-terminated character arrays
	 * @param first The first character array
	 * @param second The second character array	
	 * @return 	True - If both character arrays contain identical strings
	 *		False - Otherwise
	 */
	static inline gsBool stringCompare( const gsChar* first, const gsChar* second );
	
	/**
	 *        Concatenates the contents of \a second onto \a first
	 * @param first A pointer to the destination null-terminated character array
	 * @param second A pointer to the source null-terminated character array
	 * @param firstSize The size of the destination character array
	 * @return A pointer to the destination character array
	 */
	static inline gsChar* stringConcatenate( gsChar* first, const gsChar* second, gsUInt firstSize );
	
	///
	///	Destructor(s)
	///
	
	/**
	 *        Default Destructor
	 */
	~gsString();

	
	
	
protected:
	
	gsChar *m_buffer;
	
	gsUInt m_size;
	gsUInt m_capacity;
	
};

#endif
